package com.treeliked.netdiskdemo.util;


import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.apache.commons.lang.StringUtils;

import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * jwt 工具类
 *
 * @author lqs2
 * @date 2018-12-12, Wed
 */
public class JwtUtils {

    /**
     * 私钥
     */
    private static final String SECRET = "IM.LQS2@ICLOUD.COM";

    /**
     * 签发者
     */
    private static final String ISSUER = "TREE_LIKED";

    /**
     * JWT 添加至HTTP HEAD中的前缀
     */
    private static final String TOKEN_SEPARATOR = "Bearer ";


    /**
     * 默认加密方式
     */
    private static final Algorithm ALGORITHM = Algorithm.HMAC256(SECRET);


    /**
     * 使用默认的加解密算法及签发商创建token，不附加任何信息
     */
    public static String createDefaultToken() {
        return createDefaultToken(null);
    }


    /**
     * 使用默认的加解密算法及签发商创建token
     *
     * @param k payload中的一个键
     * @param v k对应的值
     * @return token
     */
    public static String createDefaultToken(String k, Object v) {
        return createDefaultToken(new HashMap<String, Object>(2) {{
            put(k, v);
        }});
    }


    /**
     * 使用默认的加解密算法及签发商创建token
     *
     * @param claims payload
     * @return token
     */
    public static String createDefaultToken(Map<String, Object> claims) {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.SECOND, AuthConstant.TOKEN_VALID_AGE);
        return createToken(IdUtils.get32Id(), ISSUER, claims, cal.getTime(), ALGORITHM);
    }

    /**
     * 创建token
     *
     * @param id         jwt id
     * @param issuer     签发商
     * @param claims     payload
     * @param expireDate 到期时间
     * @param alg        加解密算法
     * @return token
     */
    private static String createToken(String id, String issuer, Map<String, Object> claims, Date expireDate, Algorithm alg) {
        JWTCreator.Builder builder = JWT.create();
        builder.withIssuer(issuer).withJWTId(id);
        if (claims != null && claims.size() > 0) {
            claims.forEach((k, v) -> {
                if (v instanceof String) {
                    builder.withClaim(k, (String) v);
                    return;
                }
                if (v instanceof Integer) {
                    builder.withClaim(k, (Integer) v);
                    return;
                }
                if (v instanceof Boolean) {
                    builder.withClaim(k, (Boolean) v);
                    return;
                }
                if (v instanceof Long) {
                    builder.withClaim(k, (Long) v);
                    return;
                }
                if (v instanceof Double) {
                    builder.withClaim(k, (Double) v);
                    return;
                }
                if (v instanceof Date) {
                    builder.withClaim(k, (Date) v);
                }
            });
        }
        builder.withExpiresAt(expireDate);
        return builder.sign(alg);
    }


    /**
     * 使用默认的算法及签发商获取token id
     *
     * @param token token
     * @return id str
     */
    public static String getTokenId(String token) {
        return getDecodedJWT(token).getId();
    }

    /**
     * 使用指定的算法及签发商获取token id
     *
     * @param token  token
     * @param alg    加解密算法
     * @param issuer 签发商
     * @return id str
     */
    public static String getTokenId(String token, Algorithm alg, String issuer) {
        return getDecodedJWT(token).getId();
    }

    /**
     * 使用默认的算法及签发商根据key获取payload中的信息
     *
     * @param token token
     * @param key   key
     * @return claim
     */
    public static Claim getTokenValueByKey(String token, String key) {
        return getDecodedJWT(token).getClaim(key);
    }

    /**
     * 使用指定的算法及签发商根据key获取payload中的信息
     *
     * @param token  token
     * @param key    key
     * @param alg    加解密算法
     * @param issuer 签发商
     * @return claim
     */
    public static Claim getTokenValueByKey(String token, String key, Algorithm alg, String issuer) {
        return getDecodedJWT(token, alg, issuer).getClaim(key);
    }

    /**
     * 使用指定的算法及签发商解码token
     *
     * @param token  token
     * @param alg    加解密算法
     * @param issuer 签发商
     * @return 解码后的jwt
     */
    private static DecodedJWT getDecodedJWT(String token, Algorithm alg, String issuer) throws JWTVerificationException {
        JWTVerifier verifier = JWT.require(alg != null ? alg : ALGORITHM).withIssuer(issuer != null ? issuer : ISSUER).build();
        if (token.startsWith(TOKEN_SEPARATOR)) {
            token = token.substring(TOKEN_SEPARATOR.length());
        }
        return verifier.verify(token);
    }

    /**
     * 使用默认的算法及签发商解码token
     *
     * @param token token
     * @return 解码后的jwt
     */
    private static DecodedJWT getDecodedJWT(String token) throws JWTVerificationException {
        return getDecodedJWT(token, null, null);
    }


    /**
     * 从auth header中获取token str
     *
     * @param header auth header
     * @return token
     */
    public static String getTokenFromAuthHeader(String header) {

        if (StringUtils.isBlank(header)) {
            return null;
        }
        if (!header.startsWith(TOKEN_SEPARATOR)) {
            return header;
        }
        return header.substring(TOKEN_SEPARATOR.length());
    }
}
